/*
 * @Author: your name
 * @Date: 2021-10-12 00:29:25
 * @LastEditTime: 2021-10-12 10:12:01
 * @LastEditors: Please set LastEditors
 * @Description: In User Settings Edit
 * @FilePath: /Desktop/test.c
 */


#include <fcntl.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/types.h> 
#include <sys/wait.h>

#define MAX_LINE 80 /* The maximum length command */
char command[MAX_LINE]; // the command that was entered
// Redirect
int IO_index = 0;
int has_out = 0; // '>'
int has_in = 0; // '<'
char *fileName;


void do_redirect()
{   
    /* Redirection */
    int fd;
    int file_id;
    if (has_out) {
        // Open file - store output
        if ((file_id = open(fileName, O_CREAT|O_WRONLY, 0666)) == -1) {
            printf("open error\n");
            exit(-1);
        }
        fd = dup2(file_id, STDOUT_FILENO); // output will go to file
        if (fd == -1) { // catch error
            printf("dup2 error\n");
            exit(-1);
        }
    } else if (has_in) {
        // Open file - as input
        if ((file_id = open(fileName, O_RDONLY)) == -1) {
            printf("open error\n");
            exit(-1);
        }
        fd = dup2(file_id, STDIN_FILENO); // file content will be input
        if (fd == -1) { // catch error
            printf("dup2 error\n");
            exit(-1);
        }
    }

	// if(redirect_flag == 1)
	// {
	// 	int fd = open(redirect_file, O_WRONLY|O_CREAT|O_TRUNC, 0664);
	// 	dup2(fd, 1);
	// }
	// else if(redirect_flag == 2)
	// {
	// 	int fd = open(redirect_file, O_WRONLY|O_CREAT|O_APPEND, 0664);
	// 	dup2(fd, 1);
	// }
}


/* Copy the pointer list */
// void storePointerList(char *A[], char *B[]) {
//     int i = 0;
//     while (B[i] != NULL) {
//         char *pointer = B[i];
//         char *history = (char*)malloc(sizeof(char)*MAX_LINE);
//         for (int j = 0; j < MAX_LINE; j++) {
//             history[j] = *pointer;
//             pointer++;
//         }
//         A[i] = history;
//         i++;
//     }
//     A[i] = NULL;
// }

/* print Srgs looply*/
void showSrgs(char *A[]) {
    int i = 0;
    while (A[i] != NULL) {
        printf("%s", A[i]);
        i++;
    }
    printf("\n");
}

/* MAIN */
int main(void)
{
    /* Setting arguments:
    command line (of 80) has max of 40 arguments */
    char *args[MAX_LINE/2 + 1]; // Store current cmd
    args[0] = NULL; // command
    // char *history_args[MAX_LINE/2 + 1]; // Store history cmd
    // history_args[0] = NULL;

    /* flag to determine when to exit program */
    int should_run = 1;

    while (should_run) {
        printf("$ ");  /* prompt */
        fflush(stdout);

        /* read a command from the keyboard */
        read(0, command, MAX_LINE);

        /* parse the command */
        int cmd_index = 1;
        args[0] = command; // store the first word's pointer
        for (int i = 0; i < MAX_LINE; i++) {
            // end of word
            if (command[i] == ' ') {
                command[i] = '\0';
                args[cmd_index] = &command[i+1];
                cmd_index++;
            }
            // the last word
            else if (command[i] == '\n') {
                command[i] = '\0';
                args[cmd_index] = NULL;
                break;
            }
        }

        /* Quit */
        if (!strcmp(args[0], "quit")) {
            printf("Programme quit\n");
            should_run = 0;
            break;
        }
        
        /* Check &, whether need to go background */
        int need_wait = 1;
        if (!strcmp(args[cmd_index-1], "&")) {
            need_wait = 0;
            args[cmd_index-1] = NULL; // Remove the '&'
        }

        /* Check whether to read history */
        // if (!strcmp(args[0], "!!")) { // Done at Parent
        //     if (history_args[0] == NULL) {
        //         printf("No commands in history buffer\n");
        //         continue;
        //     } else {
        //         storePointerList(args, history_args); // load history
        //         // Show history cmd
        //         printf("History CMD: ");
        //         showSrgs(args);
        //     }
        // } else {
        //     storePointerList(history_args, args); // Store the history
        // }

        /* Redirecting */
        // int IO_index = 0;
        // int has_out = 0; // '>'
        // int has_in = 0; // '<'
        while (args[IO_index] != NULL) {
            if (!strcmp(args[IO_index], ">")) {
                has_out = 1;
                break;
            } else if (!strcmp(args[IO_index], "<")) {
                has_in = 1;
                break;
            }
            IO_index++;
        }

        /* parse the command again */
        // char *fileName;
        if (has_in | has_out) {
            fileName = args[IO_index+1]; // the next of Orientation will be the last argument
            args[IO_index] = NULL; // args should stop here
        }

        /* Pipe */
        // char *args2[MAX_LINE/2 + 1]; // Used to store the second command
        // args2[0] = NULL;
        // int pipe_index = 0;
        // int has_pipe = 0;
        // // Check whether there is a pipe
        // while (args[pipe_index] != NULL) {
        //     if (!strcmp(args[pipe_index], "|")) {
        //         has_pipe = 1;
        //         break;
        //     }
        //     pipe_index++;
        // }
        // // If has a pipe, store it (second one)
        // if (has_pipe) {
        //     int args1_index = pipe_index + 1; // raw line
        //     int args2_index = 0; // new line
        //     while (args[args1_index] != NULL) {
        //         args2[args2_index++] = args[args1_index++];
        //     }
        //     args[pipe_index] = NULL; // args should stop here
        //     args2[args2_index] = NULL; // args2 should stop here
        // }

        /*
        * After reading user input, the steps are:
        * (1) fork a child process using fork()
        * (2) the child process will invoke execvp()
        * (3) parent will invoke wait() unless command included &
        */

        // Create child process
        pid_t pid; // child process id
        int status; // child process statues
        pid = fork(); // create child process now
        // If something error, child process can not be create
        if (pid < 0) {
            printf("Parent: fork failed\n");
            return 1; // This "return" is for Parent
        }
        else if(pid == 0) { 
	    // printf("Child: now running redirection.");
            do_redirect();

			// printf("Child: now running the program, doing exec\n");
            
	    execvp(args[0], args);
			
			// if exec succeeded, the new child now starts executing the code of 
			// the main function of the xcalc program
			// The new child normally never executes the code below , unless exec failed.
	    printf("Child: exec failed, die\n");
	    return 1;  // child process dies after failed exec.
	} else {
	    // code only executed by the parent process
	    // printf("Parent: Now sleeping and waiting for child %d to end\n", pid);
            if (need_wait) {
                wait(&status); // Waiting child process finished
                // printf("Parent: Finished waiting for child, child is dead\n");
                // printf("Parent: Child exit status is %d\n", status);
            }
			
		}
        // Here is child
        // else if (pid == 0) {
        //     /* Redirection */
        //     int fd;
        //     int file_id;
        //     if (has_out) {
        //         // Open file - store output
        //         if ((file_id = open(fileName, O_CREAT|O_WRONLY, 0666)) == -1) {
        //             printf("open error\n");
        //             exit(-1);
        //         }
        //         fd = dup2(file_id, STDOUT_FILENO); // output will go to file
        //         if (fd == -1) { // catch error
        //             printf("dup2 error\n");
        //             exit(-1);
        //         }
        //     } else if (has_in) {
        //         // Open file - as input
        //         if ((file_id = open(fileName, O_RDONLY)) == -1) {
        //             printf("open error\n");
        //             exit(-1);
        //         }
        //         fd = dup2(file_id, STDIN_FILENO); // file content will be input
        //         if (fd == -1) { // catch error
        //             printf("dup2 error\n");
        //             exit(-1);
        //         }
        //     }
        //     /* pipe */
        //     if (has_pipe) {
        //         /* Create a child-child process do the args first
        //         then child process do the args2 */
        //         int fd2;
        //         int cpid; // child-child process id
        //         int cstate; // child-child process state
        //         int tempFile_id; // Used to store temporary message
        //         cpid = fork(); // child create child-child
        //         if (cpid < 0) {
        //             printf("Child: fork failed\n");
        //             return 1;
        //         }
        //         // Here is Child-Child
        //         else if (cpid == 0) {
        //             if ((tempFile_id = open("/tmp/1.txt", O_WRONLY|O_CREAT|O_TRUNC, 0666)) == -1) {
        //                 printf("open error\n");
        //                 exit(-1);
        //             }
        //             fd2 = dup2(tempFile_id, STDOUT_FILENO); // let temp file to store output
        //             execvp(args[0],args); // execute the first cmd
        //             exit(0);
        //         }
        //         // Here is the previous child (fork caller)
        //         else {
        //             waitpid(cpid, &cstate, 0);
		// 			close(fd2);
        //             if ((fd2 = open("/tmp/1.txt", O_RDONLY)) == -1) {
        //                 printf("open error\n");
        //                 exit(-1);
        //             }
		// 			dup2(fd2, STDIN_FILENO); // let temp file be the input
		// 			execvp(args2[0], args2); // execute the second one
		// 			if (remove("/tmp/1.txt") < 0) {
        //                 printf("remove error\n");
        //                 exit(-1);
        //             }
		// 			exit(0);
        //         }
        //     }
        //     // Not pipe
        //     else {
        //         execvp(args[0], args); // execute it
        //         printf("Child: exec failed, die\n");
        //         return 1; // This "return" is for Child
        //     }
        // }
        // // Here is parent
        // else {
        //     if (need_wait) {
        //         wait(&status); // Waiting child process finished
        //     }
        //     // This place no longer need a "return", because the Parent need looping
        // }
        
    }
    return 0; 
}
